package com.sven.sharedb.range.db;

import com.alibaba.druid.pool.DruidDataSource;
import com.sven.sharedb.core.constants.ShardingConstants;
import com.sven.sharedb.core.message.ObjectRestResponse;
import com.sven.sharedb.core.utils.CommonUtils;
import com.sven.sharedb.core.utils.GsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.apache.shardingsphere.infra.config.RuleConfiguration;
import org.apache.shardingsphere.infra.config.algorithm.ShardingSphereAlgorithmConfiguration;
import org.apache.shardingsphere.readwritesplitting.api.ReadwriteSplittingRuleConfiguration;
import org.apache.shardingsphere.readwritesplitting.api.rule.ReadwriteSplittingDataSourceRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * shardingsphere jdbc 读写分离配置文件
 * @Author liuxiaowo
 * @Date 2021/8/23 15:38
 **/
@Slf4j
@Configuration
@RefreshScope
@ComponentScan("com.sven.sharedb.range.db")
public class ShardingsphereJdbcReadOrWriteConfig {
    /**
     * 主库名称
     */
    @Value("${datasource.master-name}")
    private String masterDatasource;
    /**
     * 读写分离算法类型:轮询
     */
    @Value("${datasource.read-write-algorithm-type}")
    private String readWriteAlgorithmType;

    @Value("${datasource.props.sql-show:false}")
    private boolean sqlShow;

    /**
     * 获取nacos动态路径配置
     */
    @Autowired
    private ConfigurableApplicationContext configurableApplicationContext;

    /**
     * 从库名称，多个用逗号分隔
     */
    private static final String SLAVE_DATA_SOURCE = "slave-name";
    /**
     * 逗号分隔符
     */
    private static final String SPLIT_COMMA = ",";
    /**
     * 数据库规则配置名称
     */
    private static final String RULE_CONFIG_NAME = "ds";
    /**
     * 数据库规则配置负载均衡名称
     */
    private static final String RULE_CONFIG_LOAD_BALANCER_NAME = "load_balancer";
    /**
     * 数据库前缀
     */
    private static final String DB_FRONT = "datasource";
    /**
     * nacos配置分隔符
     */
    private static final String SPLIT_SPOT = ".";
    /**
     * 数据库驱动
     */
    private static final String DB_DRIVER = "driver-class-name";
    /**
     * 数据库url
     */
    private static final String DB_URL = "url";
    /**
     * 数据库用户名
     */
    private static final String DB_USER_NAME = "username";
    /**
     * 数据库密码
     */
    private static final String DB_PASSWORD = "password";
    /**
     * 数据库具体配置
     */
    private static final String DB_MIDDLE = "druid";
    /**
     * 数据库参数
     */
    private static final String DB_PARAM_FILTERS = "filters";
    private static final String DB_PARAM_INTITIAL_SIZE = "initialSize";
    private static final String DB_PARAM_MAX_ACTIVE = "maxActive";
    private static final String DB_PARAM_MAX_OPEN_PREPARED_STATEMENTS = "maxOpenPreparedStatements";
    private static final String DB_PARAM_MAX_WAIT = "maxWait";
    private static final String DB_PARAM_MIN_EVICTABLE_IDLE_TIME_MILLIS = "minEvictableIdleTimeMillis";
    private static final String DB_PARAM_MIN_IDLE = "minIdle";
    private static final String DB_PARAM_POOL_PREPARED_STATEMENTS = "poolPreparedStatements";
    private static final String DB_PARAM_TEST_ON_BORROW = "testOnBorrow";
    private static final String DB_PARAM_TEST_ON_RETURN = "testOnReturn";
    private static final String DB_PARAM_TEST_WHILE_IDLE = "testWhileIdle";
    private static final String DB_PARAM_TIME_BETWEEN_EVICTION_RUNS_MILLIS = "timeBetweenEvictionRunsMillis";
    private static final String DB_PARAM_VALIDATION_QUERRY = "validationQuery";



    /**
     * 刷新数据源
     * @return
     * @throws SQLException
     */
    @RefreshScope
    @Bean
    DataSource getDataSource() throws SQLException {
        // 从库列表
        List<String> slaveList = new ArrayList<>();
        ConfigurableEnvironment configurableEnvironment = configurableApplicationContext.getEnvironment();
        String slaveDatasource = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+SLAVE_DATA_SOURCE);
        if(StringUtils.isNotBlank(slaveDatasource)){
            String[] list = slaveDatasource.split(SPLIT_COMMA);
            for(String bean:list){
                slaveList.add(bean);
            }
        }
        List<ReadwriteSplittingDataSourceRuleConfiguration> configurations = new ArrayList<>();
        configurations.add(new ReadwriteSplittingDataSourceRuleConfiguration(RULE_CONFIG_NAME,"",masterDatasource,slaveList,RULE_CONFIG_LOAD_BALANCER_NAME));
        Map<String, ShardingSphereAlgorithmConfiguration> loadBalancers = new HashMap<>();
        // 读写分离算法类型:轮询
        loadBalancers.put(RULE_CONFIG_LOAD_BALANCER_NAME,new ShardingSphereAlgorithmConfiguration(readWriteAlgorithmType,new Properties()));
        List<RuleConfiguration> ruleConfigurationList = new ArrayList<>();

        ruleConfigurationList.add(new ReadwriteSplittingRuleConfiguration(configurations,loadBalancers));
        // 设置数据分片
        setShardingRuleConfiguration(ruleConfigurationList,configurableEnvironment);
        if(sqlShow){
            // 创建数据库列表
            Properties properties = new Properties();
            properties.put("sql-show",true);
            return ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(slaveList), ruleConfigurationList, properties);
        }
        // 创建数据库列表
        return ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(slaveList), ruleConfigurationList, new Properties());
    }

    /**
     * 设置数据分片规则
     * ruleConfigurationList sharding规则数组
     * configurableEnvironment 配置环境
     */
    private void setShardingRuleConfiguration(List<RuleConfiguration> ruleConfigurationList,ConfigurableEnvironment configurableEnvironment) {
        //获取分片表名
        String shardingTablesName = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                ShardingConstants.DB_SHARDING_TABLES_NAME_NODE);
        List<String> shardingTablesList;
        //如果表分片规则中:分片表名不存在,不设置分片规则
        if(StringUtils.isNotBlank(shardingTablesName)){
            shardingTablesList = Arrays.asList(shardingTablesName.split(SPLIT_COMMA));
        } else {
            log.error("分片表名不存在,不设置分片规则,不存在的节点:{}",DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_NAME_NODE);
            return;
        }
        //获取分片策略
        String shardingAlgorithmNames = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NODE+SPLIT_SPOT+
                ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NAMES_NODE);
        List<String> shardingAlgorithmList;
        //如果表分片规则中:分片策略不存在,不设置分片规则
        if(StringUtils.isNotBlank(shardingAlgorithmNames)){
            shardingAlgorithmList = Arrays.asList(shardingAlgorithmNames.split(SPLIT_COMMA));
        } else {
            log.error("分片策略不存在,不设置分片规则,不存在的节点:{}",DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NODE+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NAMES_NODE);
            return;
        }
        //分片策略设置
        ObjectRestResponse<Map<String,ShardingSphereAlgorithmConfiguration>> shardingAlgorithmMapResponse = this.getShardingAlgorithmMap(configurableEnvironment,shardingAlgorithmList);
        if(!CommonUtils.isSuccess(shardingAlgorithmMapResponse)){
            return;
        }
        Map<String,ShardingSphereAlgorithmConfiguration> shardingAlgorithmMap = shardingAlgorithmMapResponse.getData();
        //分片表设置
        ObjectRestResponse<List<ShardingTableRuleConfiguration>> shardingTableRuleConfigurationResponse = this.getShardingTableRuleConfigurationList(configurableEnvironment,shardingTablesList);
        if(!CommonUtils.isSuccess(shardingTableRuleConfigurationResponse)){
            return;
        }
        List<ShardingTableRuleConfiguration> shardingTableRuleConfigurationList = shardingTableRuleConfigurationResponse.getData();
        //绑定表设置
        List<String> tableBindingTableGroupsList = this.getTableBindingTableGroupsList(configurableEnvironment);
        //循环表明配置表分片规则
        ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
        //分表规则
        shardingRuleConfiguration.setShardingAlgorithms(shardingAlgorithmMap);
        //分片表设置
        shardingRuleConfiguration.setTables(shardingTableRuleConfigurationList);
        if(!CollectionUtils.isEmpty(tableBindingTableGroupsList)){
            //绑定表——联表查询防止出现笛卡尔积现象
            shardingRuleConfiguration.setBindingTableGroups(tableBindingTableGroupsList);
        }
        ruleConfigurationList.add(shardingRuleConfiguration);
    }

    /**
     * 获取分片策略设置
     * @param configurableEnvironment 配置环境
     * @param shardingAlgorithmList 分片策略名数组
     * @return 分片策略设置
     */
    private ObjectRestResponse<Map<String, ShardingSphereAlgorithmConfiguration>> getShardingAlgorithmMap(ConfigurableEnvironment configurableEnvironment,
                                                                                      List<String> shardingAlgorithmList) {

        Map<String,ShardingSphereAlgorithmConfiguration> shardingAlgorithmMap = new HashMap<>();
        for(String shardingAlgorithm : shardingAlgorithmList){
            //分片算法类型
            String shardingAlgorithmType = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NODE+SPLIT_SPOT+
                    shardingAlgorithm+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_TYPE_NODE);
            if(StringUtils.isBlank(shardingAlgorithmType)){
                log.error("分片算法类型不存在,不设置分片规则,分片策略名称:{},不存在的节点:{}",shardingAlgorithm,DB_FRONT+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NODE+SPLIT_SPOT+
                        shardingAlgorithm+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_TYPE_NODE);
                return ObjectRestResponse.error("不设置分片规则");
            }
            //分片算法参数
            String shardingAlgorithmParam = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NODE+SPLIT_SPOT+
                    shardingAlgorithm+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_PARAM_NODE);
            Properties properties = new Properties();
            if(StringUtils.isNotBlank(shardingAlgorithmParam)) {
                Map<String, String> paramMap = GsonUtils.toMaps(shardingAlgorithmParam);
                for(Map.Entry<String, String> entry : paramMap.entrySet()){
                    properties.setProperty(entry.getKey(), entry.getValue());
                }
            }
            //设置分表策略map
            shardingAlgorithmMap.put(shardingAlgorithm,new ShardingSphereAlgorithmConfiguration(shardingAlgorithmType,properties));
        }
        return ObjectRestResponse.success(shardingAlgorithmMap);
    }

    /**
     * 获取分片表设置
     * @param configurableEnvironment 配置环境
     * @param shardingTablesList 分片表名数组
     * @return 分片表设置
     */
    private ObjectRestResponse<List<ShardingTableRuleConfiguration>> getShardingTableRuleConfigurationList(ConfigurableEnvironment configurableEnvironment,
                                                                                                           List<String> shardingTablesList) {
        List<ShardingTableRuleConfiguration> shardingTableRuleConfigurationList = new ArrayList<>();
        for(String tableLogicTable : shardingTablesList){
            //表数据节点
            String tableActualDataNodes = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                    tableLogicTable+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_ACTUAL_DATA_NODES_NODE);
            //如果表分片规则中:表数据节点不存在,不设置分片规则
            if(StringUtils.isBlank(tableActualDataNodes)){
                log.error("表数据节点不存在,不设置分片规则,逻辑表名:{},不存在的节点:{}",tableLogicTable,DB_FRONT+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                        tableLogicTable+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLES_ACTUAL_DATA_NODES_NODE);
                return ObjectRestResponse.error("不设置分片规则");
            }
            //分片列名称
            String tableStrategyColumn = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                    tableLogicTable+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_COLUMN_NODE);
            if(StringUtils.isBlank(tableStrategyColumn)){
                log.error("分片列名称不存在,不设置分片规则,逻辑表名:{},不存在的节点:{}",tableLogicTable,DB_FRONT+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                        tableLogicTable+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLES_SHARDING_COLUMN_NODE);
                return ObjectRestResponse.error("不设置分片规则");
            }
            //分片算法名称
            String shardingAlgorithmName = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                    tableLogicTable+SPLIT_SPOT+
                    ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NAME_NODE);
            if(StringUtils.isBlank(shardingAlgorithmName)){
                log.error("分片算法名称不存在,不设置分片规则,逻辑表名:{},不存在的节点:{}",tableLogicTable,DB_FRONT+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                        tableLogicTable+SPLIT_SPOT+
                        ShardingConstants.DB_SHARDING_TABLES_SHARDING_ALGORITHM_NAME_NODE);
                return ObjectRestResponse.error("不设置分片规则");
            }
            //分片表配置
            ShardingTableRuleConfiguration shardingTableRuleConfiguration = new ShardingTableRuleConfiguration(tableLogicTable, tableActualDataNodes);
            //标准分片策略配置
            shardingTableRuleConfiguration.setTableShardingStrategy(new StandardShardingStrategyConfiguration(tableStrategyColumn,shardingAlgorithmName));
            shardingTableRuleConfigurationList.add(shardingTableRuleConfiguration);
        }
        return ObjectRestResponse.success(shardingTableRuleConfigurationList);
    }

    /**
     * 获取分片组
     * @param configurableEnvironment 配置环境
     * @return 分片组
     */
    private List<String> getTableBindingTableGroupsList(ConfigurableEnvironment configurableEnvironment) {
        String tableBindingTableGroups = configurableEnvironment.getProperty(DB_FRONT+SPLIT_SPOT+
                ShardingConstants.DB_SHARDING_TABLE_NODE+SPLIT_SPOT+
                ShardingConstants.DB_SHARDING_TABLES_BINDING_TABLE_GROUPS_NODE);
        if(StringUtils.isNotBlank(tableBindingTableGroups)){
            return Arrays.asList(tableBindingTableGroups.split(SPLIT_COMMA));
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * 拼接数据源
     * @param slaveList
     * @return
     */
    Map<String, DataSource> createDataSourceMap(List<String> slaveList) throws SQLException {
        // 配置真实数据源
        Map<String, DataSource> dataSourceMap = new HashMap<>();

        ConfigurableEnvironment configurableEnvironment = configurableApplicationContext.getEnvironment();
        // 配置主库
        String masterProperty = DB_FRONT+SPLIT_SPOT+masterDatasource+SPLIT_SPOT;
        DruidDataSource dataSource_master = new DruidDataSource();
        dataSource_master.setDriverClassName(configurableEnvironment.getProperty(masterProperty+DB_DRIVER));
        dataSource_master.setUrl(configurableEnvironment.getProperty(masterProperty+DB_URL));
        dataSource_master.setUsername(configurableEnvironment.getProperty(masterProperty+DB_USER_NAME));
        dataSource_master.setPassword(configurableEnvironment.getProperty(masterProperty+DB_PASSWORD));

        // 参数
        String masterDruidProperty = masterProperty+DB_MIDDLE+SPLIT_SPOT;
        dataSource_master.setFilters(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_FILTERS));
        dataSource_master.setInitialSize(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_INTITIAL_SIZE)));
        dataSource_master.setMaxActive(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_MAX_ACTIVE)));
        dataSource_master.setMaxOpenPreparedStatements(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_MAX_OPEN_PREPARED_STATEMENTS)));
        dataSource_master.setMaxWait(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_MAX_WAIT)));
        dataSource_master.setMinEvictableIdleTimeMillis(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_MIN_EVICTABLE_IDLE_TIME_MILLIS)));
        dataSource_master.setMinIdle(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_MIN_IDLE)));
        dataSource_master.setPoolPreparedStatements(Boolean.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_POOL_PREPARED_STATEMENTS)));
        dataSource_master.setTestOnBorrow(Boolean.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_TEST_ON_BORROW)));
        dataSource_master.setTestOnReturn(Boolean.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_TEST_ON_RETURN)));
        dataSource_master.setTestWhileIdle(Boolean.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_TEST_WHILE_IDLE)));
        dataSource_master.setTimeBetweenEvictionRunsMillis(Integer.valueOf(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_TIME_BETWEEN_EVICTION_RUNS_MILLIS)));
        dataSource_master.setValidationQuery(configurableEnvironment.getProperty(masterDruidProperty+DB_PARAM_VALIDATION_QUERRY));
        dataSourceMap.put(masterDatasource, dataSource_master);
        for(String bean:slaveList){
            // 配置从库
            String slaveProperty = DB_FRONT+SPLIT_SPOT+bean+SPLIT_SPOT;
            DruidDataSource dataSource_slave = new DruidDataSource();
            dataSource_slave.setDriverClassName(setSlaveParam(configurableEnvironment,slaveProperty,masterProperty,DB_DRIVER));
            dataSource_slave.setUrl(configurableEnvironment.getProperty(slaveProperty+DB_URL));
            dataSource_slave.setUsername(setSlaveParam(configurableEnvironment,slaveProperty,masterProperty,DB_USER_NAME));
            dataSource_slave.setPassword(setSlaveParam(configurableEnvironment,slaveProperty,masterProperty,DB_PASSWORD));

            // 参数
            String slaveDruidProperty = slaveProperty+DB_MIDDLE+SPLIT_SPOT;
            dataSource_slave.setFilters(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_FILTERS));
            dataSource_slave.setInitialSize(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_INTITIAL_SIZE)));
            dataSource_slave.setMaxActive(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_MAX_ACTIVE)));
            dataSource_slave.setMaxOpenPreparedStatements(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_MAX_OPEN_PREPARED_STATEMENTS)));
            dataSource_slave.setMaxWait(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_MAX_WAIT)));
            dataSource_slave.setMinEvictableIdleTimeMillis(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_MIN_EVICTABLE_IDLE_TIME_MILLIS)));
            dataSource_slave.setMinIdle(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_MIN_IDLE)));
            dataSource_slave.setPoolPreparedStatements(Boolean.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_POOL_PREPARED_STATEMENTS)));
            dataSource_slave.setTestOnBorrow(Boolean.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_TEST_ON_BORROW)));
            dataSource_slave.setTestOnReturn(Boolean.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_TEST_ON_RETURN)));
            dataSource_slave.setTestWhileIdle(Boolean.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_TEST_WHILE_IDLE)));
            dataSource_slave.setTimeBetweenEvictionRunsMillis(Integer.valueOf(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_TIME_BETWEEN_EVICTION_RUNS_MILLIS)));
            dataSource_slave.setValidationQuery(setSlaveParam(configurableEnvironment,slaveDruidProperty,masterDruidProperty,DB_PARAM_VALIDATION_QUERRY));
            dataSourceMap.put(bean, dataSource_slave);
        }
        return dataSourceMap;
    }

    /**
     * 设置从库参数,从库没有则直接从主库获取
     * @param configurableEnvironment
     * @param slaveDruidProperty
     * @param masterDruidProperty
     * @param type
     * @return
     */
    String setSlaveParam(ConfigurableEnvironment configurableEnvironment, String slaveDruidProperty, String masterDruidProperty, String type){
        String param = configurableEnvironment.getProperty(slaveDruidProperty+type);
        if(StringUtils.isBlank(param)){
            param = configurableEnvironment.getProperty(masterDruidProperty+type);
        }
        log.info("从库走主库配置:{},{},{}",slaveDruidProperty,type,param);
        return param;
    }
}